package com.duoqin.account.ui;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.duoqin.account.DuoqinAccount;
import com.duoqin.account.data.LoginRequest;
import com.duoqin.account.data.LoginResponse;
import com.duoqin.account.data.RegisterRequest;
import com.duoqin.account.viewmodel.LoginViewModel;
import com.duoqin.common.data.DefaultResponse;
import com.duoqin.common.ui.AbsActivity;
import com.duoqin.common.viewmodel.BaseViewModel;
import com.duoqin.syncassistant.R;
import com.duoqin.syncassistant.SyncAssistantApplication;


/**
 * A login screen that offers login via account/password.
 */
public class LoginActivity extends AbsActivity {

    private boolean mIsRegisterMode = false;
    // UI references.
    private EditText mAccountView;
    private EditText mPasswordView;
    private EditText mVerificationCodeView;
    private Button mRequestValidationCodeView;
    private Button mLoginOrRegisterView, mRegisterView;
    private TextView mForgetPasswordView;
    private View mProgressView;

    private LoginViewModel mViewModel;
    private String mAccount;
    private String mPassword;

    private SmsMessageReceiver mSmsReceiver = null;

    private class SmsMessageReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(TAG, "mSmsReceiver onReceive");
            Bundle extras = intent.getExtras();
            if (extras == null) return;

            try {
                String key1 = getString(R.string.key_duoqin);
                String key2 = getString(R.string.key_verification_code);
                Object[] pdus = (Object[]) extras.get("pdus");
                for (int i = 0; i < pdus.length; i++) {
                    SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i]);
                    Log.d(TAG, String.format("SMS received from %s, body: %s",
                            message.getOriginatingAddress(), message.getMessageBody()));
                    if (message.getMessageBody() != null && message.getMessageBody().contains(key1)
                            && message.getMessageBody().contains(key2)) {
                        int length = message.getMessageBody().length();
                        String code = message.getMessageBody().substring(length - 4, length);
                        // verify if it's digit
                        Integer codeValue = Integer.valueOf(code);
                        Log.d(TAG, "found verification code : " + code);
                        mVerificationCodeView.setText(code);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getIntent() != null && DuoqinAccount.INTENT_ACTION_REGISTER.equalsIgnoreCase(
                getIntent().getAction())) {
            mIsRegisterMode = true;
        }
        setContentView(R.layout.activity_login);
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE |
                WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        // Set up the login form.
        mAccountView = (EditText) findViewById(R.id.account);

        mPasswordView = (EditText) findViewById(R.id.password);
        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
                    attemptLogin();
                    return true;
                }
                return false;
            }
        });
        if (DuoqinAccount.getAccountName(getApplicationContext()) != null) {
            mAccountView.setText(DuoqinAccount.getAccountName(getApplicationContext()));
            mPasswordView.requestFocus();
        }

        mProgressView = findViewById(R.id.login_progress);
        mVerificationCodeView = findViewById(R.id.verification_code);
        mLoginOrRegisterView = findViewById(R.id.login_or_register);
        mLoginOrRegisterView.setOnClickListener(this);
        mRequestValidationCodeView = findViewById(R.id.request_verification_code);
        mRegisterView = findViewById(R.id.register);
        mRegisterView.setOnClickListener(this);
        mForgetPasswordView = findViewById(R.id.forget_password);
        mForgetPasswordView.setText(Html.fromHtml(
                getString(R.string.url_link, getString(R.string.forget_password))));
        mForgetPasswordView.setOnClickListener(this);

        setupRegisterModeView();

        setupModelObserver();

        mSmsReceiver = new SmsMessageReceiver();
        registerReceiver(mSmsReceiver,
                new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        if (intent != null && DuoqinAccount.INTENT_ACTION_REGISTER.equalsIgnoreCase(
                getIntent().getAction())) {
            mIsRegisterMode = true;
        }
        setupRegisterModeView();
    }

    private void setupRegisterModeView() {
        if (mIsRegisterMode) {
            setupTitle(getString(R.string.action_register));
            mPasswordView.setVisibility(View.GONE);
            mVerificationCodeView.setVisibility(View.GONE);
            mLoginOrRegisterView.setVisibility(View.GONE);
            mLoginOrRegisterView.setText(R.string.action_register);
            mRequestValidationCodeView.setVisibility(View.VISIBLE);
            mRequestValidationCodeView.setOnClickListener(this);
            mRegisterView.setVisibility(View.GONE);
            mForgetPasswordView.setVisibility(View.GONE);
        } else {
            setupTitle(getString(R.string.action_sign_in));
            mRegisterView.setVisibility(View.VISIBLE);
            mForgetPasswordView.setVisibility(View.VISIBLE);
        }
    }

    private void setupModelObserver() {
        mViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);

        final Observer<LoginResponse> loginResponseObserver =
                new Observer<LoginResponse>() {
                    @Override
                    public void onChanged(@Nullable final LoginResponse response) {
                        Log.i(TAG, "onChanged LoginResponse = " + response);
                        if (response != null) {
                            Log.d(TAG, "onChanged code = " + response.getCode()
                                    + "; msg = " + response.getMsg());
                            Log.d(TAG, "onChanged data = " + response.getData());
                            if (BaseViewModel.SERVER_RESULT_SUCCESS == response.getCode()) {
                                if (response.getData() != null) {
                                    DuoqinAccount.addAccount(getApplicationContext(), mAccount,
                                            null, response.getData());
                                }
                                setResult(RESULT_OK);
                                finish();
                                return;
                            } else if (BaseViewModel.SERVER_RESULT_ERROR_INVALID_PASSWORD
                                    == response.getCode()) {
                                Toast.makeText(getApplicationContext(),
                                        R.string.error_incorrect_password, Toast.LENGTH_SHORT).show();
                                mRegisterView.setVisibility(View.VISIBLE);
                                mPasswordView.requestFocus();
                            }
                        }
                        Log.w(TAG, "error_login_fail");
                        showProgress(false, true);
                    }
                };
        mViewModel.loginResponse().observe(this, loginResponseObserver);

        final Observer<LoginResponse> registerResponseObserver =
                new Observer<LoginResponse>() {
                    @Override
                    public void onChanged(@Nullable final LoginResponse response) {
                        Log.i(TAG, "onChanged registerResponse = " + response);
                        if (response != null) {
                            Log.d(TAG, "onChanged code = " + response.getCode()
                                    + "; msg = " + response.getMsg());
                            Log.d(TAG, "onChanged data = " + response.getData());
                        }
                        if (response != null) {
                            if (BaseViewModel.SERVER_RESULT_SUCCESS == response.getCode()) {
                                if (response.getData() != null) {
                                    DuoqinAccount.addAccount(getApplicationContext(), mAccount,
                                            null, response.getData());
                                }
                                setResult(RESULT_OK);
                                finish();
                                return;
                            } else if (BaseViewModel.SERVER_RESULT_ERROR_INVALID_PARA
                                    == response.getCode()) {
                                Toast.makeText(getApplicationContext(),
                                        R.string.error_incorrect_validation,
                                        Toast.LENGTH_SHORT).show();
                                mVerificationCodeView.requestFocus();
                            }
                        }
                        Log.w(TAG, "error_register_fail");
                        showProgress(false, true);
                    }
                };

        mViewModel.registerResponse().observe(this, registerResponseObserver);

        final Observer<DefaultResponse> validationCodeResponseObserver =
                new Observer<DefaultResponse>() {
                    @Override
                    public void onChanged(@Nullable final DefaultResponse response) {
                        Log.i(TAG, "onChanged validationCodeResponse = "
                                + response);
                        if (response != null) {
                            Log.i(TAG, "onChanged code = " + response.getCode()
                                    + "; msg = " + response.getMsg());
                            if (BaseViewModel.SERVER_RESULT_SUCCESS
                                    == response.getCode()) {
                                mPasswordView.setVisibility(View.VISIBLE);
                                mVerificationCodeView.setVisibility(View.VISIBLE);
                                mLoginOrRegisterView.setVisibility(View.VISIBLE);
                                mRequestValidationCodeView.setVisibility(View.GONE);
                                mPasswordView.requestFocus();
                                Toast.makeText(getApplicationContext(),
                                        R.string.validation_code_sent, Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                };
        mViewModel.validationCodeResponse().observe(this, validationCodeResponseObserver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mSmsReceiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (SyncAssistantApplication.getsInstance().hasLogin()) {
            finish();
        }
    }

    @Override
    public void onClick(View v) {
        if (R.id.register == v.getId()) {
            if (!mIsRegisterMode) {
                mIsRegisterMode = true;
                setupRegisterModeView();
            }
        } else if (R.id.forget_password == v.getId()) {
            mIsRegisterMode = true;
            setupRegisterModeView();
            setupTitle(getString(R.string.reset_password));
        } else if (R.id.login_or_register == v.getId()) {
            mRegisterView.setVisibility(View.GONE);
            attemptLogin();
        } else if (R.id.request_verification_code == v.getId()) {
            getValidationCode();
        } else {
            super.onClick(v);
        }
    }

    private void getValidationCode() {
        String account = mAccountView.getText().toString();
        if (TextUtils.isEmpty(account) || !isAccountValid(account)) {
            Toast.makeText(getApplicationContext(), getString(R.string.error_invalid_account),
                    Toast.LENGTH_SHORT).show();
            mAccountView.requestFocus();
        } else {
            // TODO set timer
            mRequestValidationCodeView.setEnabled(false);
            mViewModel.requestValidationCode(account);
//            mPasswordView.setVisibility(View.VISIBLE);
//            mVerificationCodeView.setVisibility(View.VISIBLE);
//            mLoginOrRegisterView.setVisibility(View.VISIBLE);
//            mRequestValidationCodeView.setVisibility(View.GONE);
//            mPasswordView.requestFocus();
//            Toast.makeText(getApplicationContext(), R.string.validation_code_sent,
//                    Toast.LENGTH_SHORT).show();
        }
    }

    private void attemptLogin() {
        // Store values at the time of the login attempt.
        mAccount = mAccountView.getText().toString();
        mPassword = mPasswordView.getText().toString();
        String verificationCode = mVerificationCodeView.getText().toString();

        boolean cancel = false;
        View focusView = null;

        // Check for a valid account.
        if (TextUtils.isEmpty(mAccount) || !isAccountValid(mAccount)) {
            Toast.makeText(getApplicationContext(), getString(R.string.error_invalid_account),
                    Toast.LENGTH_SHORT).show();
            mRegisterView.setVisibility(View.VISIBLE);
            focusView = mAccountView;
            cancel = true;
        } else if (mIsRegisterMode) {
            if (TextUtils.isEmpty(verificationCode) || !isPasswordValid(verificationCode)) {
                Toast.makeText(getApplicationContext(), getString(R.string.error_invalid_validation),
                        Toast.LENGTH_SHORT).show();
                focusView = mVerificationCodeView;
                cancel = true;
            }
        } else {
            if (TextUtils.isEmpty(mPassword) || !isPasswordValid(mPassword)) {
                Toast.makeText(getApplicationContext(), getString(R.string.error_invalid_password),
                        Toast.LENGTH_SHORT).show();
                mRegisterView.setVisibility(View.VISIBLE);
                focusView = mPasswordView;
                cancel = true;
            }
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // Show a progress spinner, and kick off a background task to
            // perform the user login attempt.
            showProgress(true, false);

            TelephonyManager telephonyMgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
            String imei = telephonyMgr.getDeviceId();
            Log.d(TAG, "imei = " + imei + "; HwModel = " + Build.MODEL);
            if (mIsRegisterMode) {
                RegisterRequest registerRequest = new RegisterRequest();
                registerRequest.setMobile(mAccount);
                registerRequest.setPassword(mPassword);
                registerRequest.setSn(Build.SERIAL);
                registerRequest.setImei(imei);
                registerRequest.setHwModel(Build.MODEL);
                mViewModel.register(mAccount, verificationCode, registerRequest);
            } else {
                LoginRequest loginRequest = new LoginRequest();
                loginRequest.setMobile(mAccount);
                loginRequest.setPassword(mPassword);
                loginRequest.setImei(imei);
                loginRequest.setHwModel(Build.MODEL);
                mViewModel.login(loginRequest);
            }
        }
    }

    private boolean isAccountValid(String account) {
        return (account != null && account.startsWith("1") && account.length() == 11);
    }

    private boolean isPasswordValid(String password) {
        //TODO: Replace this with your own logic
        return password.length() > 0;
    }

    /**
     * Shows the progress UI and hides the login form.
     */
    private void showProgress(final boolean show, final boolean requestFocus) {
        mLoginOrRegisterView.setVisibility(show ? View.GONE : View.VISIBLE);

        int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
        mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
        mProgressView.animate().setDuration(shortAnimTime).alpha(
                show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
                if (requestFocus) {
                    mLoginOrRegisterView.requestFocus();
                }
            }
        });
    }
}

